Eager parsing fully parses and compiles all code immediately, while lazy parsing (also called preparsing) skips detailed analysis of function bodies until they are actually called, significantly reducing startup time and memory usage at the cost of a slight delay on first function invocation.
Eager and lazy parsing are two strategies JavaScript engines use to balance fast startup with eventual execution performance. Eager parsing builds a complete Abstract Syntax Tree (AST) for all code, including function bodies, immediately. Lazy parsing delays full parsing of inner functions until they are called, only performing a quick superficial scan (preparsing) initially. Modern engines like V8 use lazy parsing by default for functions not immediately executed, as most functions in a typical web application are never called during initial page load.
Process: The parser builds a complete AST for the entire code, including all nested function bodies, performing full syntax checking .
Memory usage: Stores the full AST in memory for all functions, which can be substantial for large codebases .
Time: Takes longer initially because every function body must be processed, even those never called .
Execution: Functions can execute immediately with zero additional parsing delay, as they're already fully parsed .
Use cases: Critical startup code, immediately-invoked function expressions (IIFEs), and code that will definitely run soon .
Process: The parser quickly skims function bodies, validating basic syntax (no unbalanced braces) but not building a full AST. It records just enough information (scope, parameter count) to parse later if needed .
Memory usage: Minimal—only stores a small placeholder for each function instead of the full AST .
Time: Much faster initially, as the parser avoids detailed work on function bodies .
Execution: First call to a lazily-parsed function triggers a full eager parse at that moment, causing a small delay .
Use cases: Most functions that are not immediately executed, event handlers, utility functions called later .
The performance impact of lazy parsing is substantial. According to V8 team measurements, lazy parsing reduces memory usage by approximately 30-40% and parse time by 40-60% on typical web pages . This is because most functions on a page are not immediately executed—they're event handlers, library code, or functions defined but called later. Without lazy parsing, all this code would waste memory and CPU during startup.
Preparser: V8 includes a fast preparser that validates syntax and collects scope information (like which variables are declared) without building AST nodes .
LazyCompilation flag: Functions are marked as 'lazy' in the bytecode, triggering full parse on first call .
Inner functions: If a function is lazily parsed, its inner functions are also lazily parsed, creating a chain of lazy compilation .
Arrow functions: Treated similarly to regular functions—lazily parsed unless immediately invoked .
Function expressions: The parsing strategy depends on context—if assigned to a variable and not called immediately, they're lazy .
IIFEs are eager: Functions wrapped in parentheses and immediately invoked (e.g., (function() { ... })()) are eagerly parsed because they execute right away .
Function constructors: new Function('...') triggers parsing at call time, similar to lazy but with full string evaluation .
eval(): Forces eager parsing of the evaluated code at runtime, bypassing lazy optimizations .
Debugger impact: When DevTools is open, V8 may parse more eagerly to provide better debugging information .
Module scripts: ES6 modules are parsed eagerly because the spec requires static analysis for imports/exports .
For developers, understanding lazy parsing helps in structuring code for optimal startup performance. Critical path code should be kept at the top level or in IIFEs to ensure eager parsing. Non-critical functions (event handlers, callbacks) should remain lazily parsed. Tools like Webpack's code splitting can help by separating code into chunks that are parsed only when needed. Modern bundlers also implement 'optimize for parsing' techniques, such as marking certain functions as immediately invoked to hint eager parsing to the engine.